  

/*-------------------------------------------------------------------------
 *
 * buf_table.c
 *	  用于将 BufferTags 映射到缓冲区索引的例程。
 *
 * 注意：此文件中的例程不执行自身的锁定。调用者必须持有对适当 BufMappingLock 的适当锁，如评论中所述。我们无法在这些函数内部进行锁定，因为在大多数情况下，调用者需要在释放锁之前调整缓冲区头的内容（请参阅 README 中的注释）。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/storage/buffer/buf_table.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "storage/buf_internals.h"
#include "storage/bufmgr.h"

/* 缓冲查找哈希表的条目 */
typedef struct
{
	BufferTag	key;			/* 磁盘页的标签 */
	int			id;				/* 相关缓冲区 ID */
} BufferLookupEnt;

static HTAB *SharedBufHash;


/*
 * 估算映射哈希表所需的空间
 *		大小是所需的哈希表大小（可能大于 NBuffers）
 */
Size BufTableShmemSize(int fc_size)
{
	return hash_estimate_size(fc_size, sizeof(BufferLookupEnt));
}

/*
 * 初始化共享内存哈希表以映射缓冲区
 *		大小是所需的哈希表大小（可能大于 NBuffers）
 */
void InitBufTable(int fc_size)
{
	HASHCTL		fc_info;

	/* 假设尚不需要锁定 */

	/* BufferTag 映射到 Buffer */
	fc_info.keysize = sizeof(BufferTag);
	fc_info.entrysize = sizeof(BufferLookupEnt);
	fc_info.num_partitions = NUM_BUFFER_PARTITIONS;

	SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
								  fc_size, fc_size,
								  &fc_info,
								  HASH_ELEM | HASH_BLOBS | HASH_PARTITION);
}

/*
 * BufTableHashCode
 *		计算与 BufferTag 关联的哈希码
 *
 * 这必须与标签一起传递给查找/插入/删除例程。
 * 我们这样做是因为调用者需要知道哈希码以确定要锁定哪个缓冲区分区，而我们不想进行两次哈希计算（hash_any 有点慢）。
 */
uint32 BufTableHashCode(BufferTag *fc_tagPtr)
{
	return get_hash_value(SharedBufHash, (void *) fc_tagPtr);
}

/*
 * BufTableLookup
 * 查找给定的 BufferTag；返回缓冲区 ID，如果未找到则返回 -1
 *
 * 调用者必须持有 BufMappingLock 的共享锁以访问该标签的分区
 */
int BufTableLookup(BufferTag *fc_tagPtr, uint32 fc_hashcode)
{
	BufferLookupEnt *fc_result;

	fc_result = (BufferLookupEnt *)
		hash_search_with_hash_value(SharedBufHash,
									(void *) fc_tagPtr,
									fc_hashcode,
									HASH_FIND,
									NULL);

	if (!fc_result)
		return -1;

	return fc_result->id;
}

/*
 * BufTableInsert
 * 为给定标签和缓冲区 ID 插入一个哈希表项，除非该标签的条目已经存在
 *
 * 在成功插入时返回 -1。如果已经存在冲突条目，则返回该条目的缓冲区 ID。
 *
 * 调用者必须持有 BufMappingLock 的排他锁以访问该标签的分区
 */
int BufTableInsert(BufferTag *fc_tagPtr, uint32 fc_hashcode, int fc_buf_id)
{
	BufferLookupEnt *fc_result;
	bool		fc_found;

	Assert(fc_buf_id >= 0);		/* -1 保留用于未在表中 */
	Assert(fc_tagPtr->blockNum != P_NEW);	/* 无效的标签 */

	fc_result = (BufferLookupEnt *)
		hash_search_with_hash_value(SharedBufHash,
									(void *) fc_tagPtr,
									fc_hashcode,
									HASH_ENTER,
									&fc_found);

	if (fc_found)					/* 已找到表中已有内容 */
		return fc_result->id;

	fc_result->id = fc_buf_id;

	return -1;
}

/*
 * BufTableDelete
 * 删除给定标签的哈希表条目（该条目必须存在）
 *
 * 调用者必须持有 BufMappingLock 的排他锁以访问该标签的分区
 */
void BufTableDelete(BufferTag *fc_tagPtr, uint32 fc_hashcode)
{
	BufferLookupEnt *fc_result;

	fc_result = (BufferLookupEnt *)
		hash_search_with_hash_value(SharedBufHash,
									(void *) fc_tagPtr,
									fc_hashcode,
									HASH_REMOVE,
									NULL);

	if (!fc_result)				/* 不应该发生 */
		elog(ERROR, "shared buffer hash table corrupted");
}
